﻿using Microsoft.Extensions.Options;
using StackExchange.Redis;
using System.Collections.Concurrent;

namespace Singer.Middleware.Redis;

/// <summary>
/// Redis连接池服务
/// </summary>
public class RedisConnectionPool : IRedisConnectionPool
{
    RedisOptions Options;
    ConcurrentDictionary<string, IConnectionMultiplexer> ConnectionPool = new ConcurrentDictionary<string, IConnectionMultiplexer>();
    bool IsDisposed; // 是否已GC回收

    public RedisConnectionPool(IOptions<RedisOptions> options)
    {
        Options = options.Value;
    }

    public IConnectionMultiplexer GetConnection(string connectionName)
    {
        return Init(connectionName);
    }

    public IDatabase GetDatabase(int db = -1, string? connectionName = null)
    {
        var conn = Init(connectionName);
        return conn.GetDatabase(db);
    }

    private IConnectionMultiplexer Init(string? connectionName = null)
    {
        if (string.IsNullOrWhiteSpace(connectionName))
            connectionName = RedisOptions.DefaultName;
        var connectionString = Options.Get(connectionName);
        ConfigurationOptions opts = ConfigurationOptions.Parse(connectionString);
        if (!string.IsNullOrWhiteSpace(Options.InstanceName))
            opts.ChannelPrefix = Options.InstanceName.TrimEnd(':') + ":";
        IConnectionMultiplexer connection = ConnectionMultiplexer.Connect(opts);
        if (connection == null)
            throw new Exception($"【Redis】The '{connectionName}' connection failed.");
        var conn = ConnectionPool.GetOrAdd(connectionName, connection);
        return conn;
    }

    public void Dispose()
    {
        if (IsDisposed)
            return;
        foreach (var connection in ConnectionPool)
        {
            try
            {
                connection.Value.Dispose();
            }
            catch (Exception)
            {
            }
        }
        ConnectionPool.Clear();
        IsDisposed = true;
    }
}
